import os
import subprocess
import sys
from typing import Optional

from .lexer import Lexer
from .parser import Parser
from .sema import TypeChecker
from .codegen import IRGenerator

class Compiler:
    def __init__(self):
        pass

    def compile_file(self, source_path: str, output_path: Optional[str] = None):
        if not output_path:
            output_path = os.path.splitext(source_path)[0] + ".exe"
            
        with open(source_path, 'r', encoding='utf-8') as f:
            code = f.read()
            
        # 1. 前端
        print(f"编译 {source_path}...")
        try:
            lexer = Lexer(code)
            tokens = lexer.tokenize()
            
            parser = Parser(tokens)
            program = parser.parse()
            print(f"DEBUG: Program AST: {program}")
            for i, defn in enumerate(program.definitions):
                print(f"DEBUG: Definition {i}: {defn}")
            
            # 2. 语义分析
            checker = TypeChecker()
            checker.check_program(program)
            
            # 3. 代码生成
            generator = IRGenerator()
            ir_code = generator.generate(program)
            
            # 4. 写入 IR 文件
            ir_path = os.path.splitext(source_path)[0] + ".ll"
            with open(ir_path, 'w', encoding='utf-8') as f:
                f.write(ir_code)
        except Exception as e:
            import traceback
            traceback.print_exc()
            print(f"编译失败: {e}")
            return
            f.write(ir_code)
            
        # 5. 使用 llc 编译 IR 到 Object 文件
        obj_path = os.path.splitext(source_path)[0] + ".obj"
        # 检查 llc 是否在路径中
        llc_cmd = ["llc", "-filetype=obj", "-o", obj_path, ir_path]
        print(f"运行: {' '.join(llc_cmd)}")
        try:
            subprocess.run(llc_cmd, check=True, capture_output=True)
        except subprocess.CalledProcessError as e:
            print(f"运行 llc 时出错:\n{e.stderr.decode()}")
            return
            
        # 6. 使用 clang 链接
        # 需要链接 C 运行时 (CRT)
        # Clang 通常在作为驱动程序调用时处理此问题
        clang_cmd = ["clang", "-o", output_path, obj_path]
        print(f"运行: {' '.join(clang_cmd)}")
        try:
            subprocess.run(clang_cmd, check=True, capture_output=True)
        except subprocess.CalledProcessError as e:
            print(f"运行 clang 时出错:\n{e.stderr.decode()}")
            return
            
        print(f"编译成功！输出: {output_path}")

def main():
    import argparse
    
    parser = argparse.ArgumentParser(description='墨算 (InkLang) 编译器')
    parser.add_argument('source_file', help='墨算源文件路径')
    parser.add_argument('-r', '--run', action='store_true', help='编译后运行程序')
    parser.add_argument('-d', '--delete', action='store_true', help='删除编译过程中产生的中间文件')
    parser.add_argument('-o', '--output', help='指定输出文件路径')
    
    args = parser.parse_args()
    
    source_file = args.source_file
    compiler = Compiler()
    compiler.compile_file(source_file, args.output)
    
    # 获取中间文件路径
    base_path = os.path.splitext(source_file)[0]
    ir_path = base_path + ".ll"
    obj_path = base_path + ".obj"
    exe_path = args.output if args.output else base_path + ".exe"
    
    # 如果请求运行
    if args.run:
        if os.path.exists(exe_path):
            print(f"\n运行 {exe_path}...")
            print("=" * 50)
            result = subprocess.run([exe_path], capture_output=False)
            print("=" * 50)
            print(f"程序退出，返回码: {result.returncode}")
    
    # 如果请求删除中间文件
    if args.delete:
        print("\n清理中间文件...")
        for file_path in [ir_path, obj_path]:
            if os.path.exists(file_path):
                os.remove(file_path)
                print(f"  已删除: {file_path}")

if __name__ == '__main__':
    main()
